En la administración y cuantificación de riesgos, la volatilidad \(σ_{i,t}\) juega un papel central para medir pérdidas potenciales, ya que indica cuál es la fluctuación de la rentabilidad o del precio de un activo con respecto a su cotización media histórica. Este concepto es de alta utilidad, puesto que a mayor volatilidad de un activo, mayor es el riesgo de que la rentabilidad sea distinta a la esperada.
Para calcular la volatilidad y con ello poder comparar las volatilidades de un activo con la de otros se utiliza la desviación estándar, pues ofrece información sobre la volatilidad que ha tenido un activo en el pasado de forma resumida.
Incialmente, la volatilidad será la diferencia entre lo que se espera \(E_{r,t}\) y lo que realmente se tiene \(r_{i,t}\). Una primera aproximación de volatilidad se da por la ecuación:
\[\begin{align} σ_{i,t} = \sqrt{\frac{\sum(r_{i,t}-E_{r,t})^2}{t-1}} \end{align}\]
La cual otorga a cada una una de las observaciones la misma ponderación en el tiempo, esto se traduce en que una observación antigüa tiene el mismo peso que una reciente.
Teniendo en cuenta este fenómeno variante se considerarán 3 tipos de volatilidad:
La volatilidad convencional o fija en el tiempo es la más empleada debido a su simplicidad y facil implementación.
Ésta se interprea como una medida de dispersión para entender cuánto varian los datos en relación con la media del conjunto de datos. Esto permite reconocer la variabilidad dentro de los datos, lo cual resulta escencial para comprender las inconsistencias de las mediciones, de esta forma al comparar desviaciones estándar es posible evaluar la variabilidad de la siguiente forma:
Como se mencionó anteriormente, la desviación estándar posee algunas limitaciones como:
A diferencia de la volatilidad convencional, la volatilidad exponencial da un mayor peso a las observaciones recientes y menos a las antiguas. De esta forma, aplicando un peso \(\lambda\) y utilizando la fórmula para el promedio movil ponderado, se tendrá la siguiente formulación:
\[\begin{align} PME = \frac{\sum_{n=1}^{t} r_{i,t-n} * \lambda^{n-1} }{\sum_{n=0}^{t-2} \lambda^n} \end{align}\]
donde \(\lambda\) es el factor de suavizamiento y \(r_{i,t}\) es la variación porcentual de los precios de cierre de los activos estudiados en el rezago t-n. \(\lambda \epsilon [0,1]\) permitiendo que las observaciones más lejanas tiendan a 0, ie, mientras n crece.
Aplicando la formulación anterior, para una serie de rendimientos al cuadrado, se llegará a la varianza con suavizamiento exponencial \(\hat{σ_{i,t}}\) dada por:
\[\begin{align} \hat{σ_{i,t}}= (1-\lambda) \sum_{n = 1}^{\infty} \lambda^{n-1} r_{i,t-1}^{2} \end{align}\]
Otra forma de calcular la varianza con suavizamiento exponencial es implementando la siguiente fórmula recursiva:
\[\begin{align} \hat{σ_{i,t}}= \sqrt{(1-\lambda) r_{i,t-1}^{2} + \lambda \hat{σ_{i,t-1}}^{2}} \end{align}\]
Notese que en todos estos cálculos, el valor de \(\lambda\) es crucial para el resultado, por lo que se debe seleccionar el valor adecuado u óptimo que permita evitar la sobre o subestimación de la pérdida potencial.
Nótese que al aplicar la volatilidad con suavizamiento exponencial permite implementar un análisis donde los datos más recientes son los que más información aportan, sin embargo, el hecho de incorporar este efecto, genera una alta dependencia sobre un valor \(\lambda\) que puede ser subjetiva y afectar los resultados.
A partir de la volatilidad con suavizamiento exponencial es posible concluir que la volatilidad no necesariamente tiene que ser constante en el tiempo, más aún, este valor puede estar oscilando cerca de un valor de largo plazo, \(\omega = σ_{0}\).
En este sentido, los modelos GARCH permiten que el valor de \(\hat{σ_{i,t}}\) parta de una magnitud inercial o fija:
\[\begin{align} \hat{σ_{GARCH,i,t}}= \omega + \beta_{1} r_{i,t-1} ^{2} + \gamma_{1} \hat{σ_{i,t-1}}^{2} \end{align}\]
Notese la similitud con el modelo de suavizamiento exponencial, con \(\beta_{1}=1-\lambda\) y \(\gamma_{1}=\lambda\), la diferencia radica en la introducción de un valor inercial o fijo de la volatilidad \(\alpha\). Estos coeficientes se estiman por medio de métodos numéricos o de optimización.
Así, el modelo \(\hat{σ_{GARCH,i,t}}\) es el mejor, puesto que permite que la volatilidad cambie en el tiempo y se hagan pronósticos de volatilidad en t+n.
Este modelo cumple:
El modelo GARCH también tiene una forma recursiva, dada por:
\[\begin{align} \hat{σ_{GARCH,i,t}}= \alpha + \sum_{p=1}^{P} \beta_{p} r_{i,t-p} ^{2} + \sum_{q=1}^{Q} \gamma_{q} \hat{σ_{i,t-q}}^{2} \end{align}\]
Para determinar el mejor modelo con P y Q rezagos se utiliza el criterio de información de Akaike (AIC), Bayesiano (BIC) para determinar el mejor modelo.
El conglomerado de volatilidades o volatility clustering es un fenómeno de los mercados financieros y series de precios de los activos. Este describe la tendencia de los mercados a experimentar periodos de alta volatilidad seguidos de otros periodos de alta volatilidad, así como periodods de baja volatilidad seguidos de periodos de baja volatilidad, esto es, la volatilidad tiende a agruparse en el tiempo creando conglomerados o clusters con comportamiento similar.
Si bien, los rendimientos en sí mismos no están correlacionados, los rendimientos absolutos \(|r_{t}|\) o sus cuadrados muestran una correlación positiva, significativa que decae lentamente. Las observaciones de este tipo de series temporales va contra los modelos simples llevando al uso de modelos GARCH y de volatilidad estocástica que revierten la media en la predición.
Los modelos GARCH están diseñados para capturar la heterocedasticidad condicional, la cual es la principal característica de los conglomerados, mediante los siguientes procesos:
A continuación se presenta una tabla que compara los diversos métodos para el cálculo de la volatilidad.
| Método | Ventajas | Desventajas |
|---|---|---|
| Desviación estándar o fija en el tiempo | Es el más simple y proporciona un cálculo fijo en el tiempo. | Da el mismo peso a todos los datos, se ve afectado por datos atípicos. |
| Desviación con suavizamiento exponencial | Asigna mayor peso a las observaciones recientes | No necesariamente la distribución es exponencial, introduce un termino de alta dependencia \(\lambda\) |
| Modelo GARCH | Usa información pasada para mejorar el proceso, capta el fenómeno de aglomerado de volatilidades. | Es más complejo que los otros modelos, y puede ser más pesado en términos computacionales. |
Para ilustrar mejor el cálculo de volatilidades anteriormente explicado se hará el calculo cuantitativo de estas en el fondo QQQ desde 20/11/2023 hasta 20/11/2024.
La volatilidad convencional será:
sigma_fija=sd(rendimientos)
sigma_fija
## [1] 1.097977
La volatilidad con suavizamiento exponencial al 0.95 y 0.98:
# Volatilidad con suavizamiento exponencial con lambda=0.95:
sigma95Lambda=funEWSigma(rendimientos,0.95)
# Volatilidad con suavizamiento exponencial con lambda=0.98:
sigma98Lambda=funEWSigma(rendimientos,0.98)
La volatilidad GARCH con función gaussiana:
# Se crea el objeto spec del modelo GARCH:
modeloGARCH=ugarchspec(variance.model = list(model = "sGARCH",
garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0),
include.mean = FALSE),
distribution.model = "norm")
# Se ajusta el modelo GARCH:
ajusteGARCH_NORM=ugarchfit(spec=modeloGARCH, data=rendimientos)
coeficientesGARCH=data.frame(coeficientes=ajusteGARCH_NORM@fit$coef,
errores=ajusteGARCH_NORM@fit$robust.se.coef,
valoresT=ajusteGARCH_NORM@fit$tval,
Pvalues=2*(1-pt(abs(ajusteGARCH_NORM@fit$tval),df=length(rendimientos)-3))
)
# Desviación estándar GARCH:
sigmaGARCH_GAUSS=funGARCH(rendimientos,model="sGARCH",LLF="norm",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE)
sigmaGARCH_GAUSS
## [1] 1.185836
La volatilidad GARCH con función t-Student:
# Se crea el objeto spec del modelo GARCH:
modeloGARCH=ugarchspec(variance.model = list(model = "sGARCH",
garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0),
include.mean = FALSE),
distribution.model = "std")
# Se ajusta el modelo GARCH:
ajusteGARCH_STD=ugarchfit(spec=modeloGARCH, data=rendimientos)
coeficientesGARCH=data.frame(coeficientes=ajusteGARCH_STD@fit$coef,
errores=ajusteGARCH_STD@fit$robust.se.coef,
valoresT=ajusteGARCH_STD@fit$tval,
Pvalues=2*(1-pt(abs(ajusteGARCH_STD@fit$tval),df=length(rendimientos)-3))
)
# Desviación estándar GARCH:
sigmaGARCH_std=funGARCH(rendimientos,model="sGARCH",LLF="std",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE)
sigmaGARCH_std
## [1] 1.198438
La volatilidad GARCH con función GED:
# Se crea el objeto spec del modelo GARCH:
modeloGARCH=ugarchspec(variance.model = list(model = "sGARCH",
garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0),
include.mean = FALSE),
distribution.model = "ged")
# Se ajusta el modelo GARCH:
ajusteGARCH_GED=ugarchfit(spec=modeloGARCH, data=rendimientos)
coeficientesGARCH=data.frame(coeficientes=ajusteGARCH_GED@fit$coef,
errores=ajusteGARCH_GED@fit$robust.se.coef,
valoresT=ajusteGARCH_GED@fit$tval,
Pvalues=2*(1-pt(abs(ajusteGARCH_GED@fit$tval),df=length(rendimientos)-3))
)
# Desviación estándar GARCH:
sigmaGARCH_GED=funGARCH(rendimientos,model="sGARCH",LLF="ged",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE)
sigmaGARCH_GED
## [1] 1.189749
Calculo de volatilidad con GJR-GARCH (asimétrico) con función de verosimilitud gaussiana:
# Se especifica el modelo GJR-GARCH
gjr_spec <- ugarchspec(
mean.model = list(armaOrder = c(0, 0)),
variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
distribution.model = "norm"
)
gjr_fit_norm <- ugarchfit(spec = gjr_spec, data = rendimientos)
var_cond_norm <- sigma(gjr_fit_norm)^2
desviacion_estandar_norm <- sqrt(var_cond_norm)
Calculo de volatilidad con GJR-GARCH (asimétrico) con función de verosimilitud t-Student:
# Se especifica el modelo GJR-GARCH
gjr_spec <- ugarchspec(
mean.model = list(armaOrder = c(0, 0)),
variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
distribution.model = "std"
)
gjr_fit_std <- ugarchfit(spec = gjr_spec, data = rendimientos)
var_cond_std <- sigma(gjr_fit_std)^2
desviacion_estandar_std <- sqrt(var_cond_std)
Calculo de volatilidad con GJR-GARCH (asimétrico) con función de verosimilitud GED:
# Se especifica el modelo GJR-GARCH
gjr_spec <- ugarchspec(
mean.model = list(armaOrder = c(0, 0)),
variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
distribution.model = "ged"
)
gjr_fit_ged <- ugarchfit(spec = gjr_spec, data = rendimientos)
var_cond_ged <- sigma(gjr_fit_ged)^2
desviacion_estandar_ged <- sqrt(var_cond_ged)
Se utiliza el criterio Akaike, con la función AIC:
Ahora para futuras aplicaciones de backtesting, se utilizarán los datos desde el 20 de noviembre de 2019 con periodicidad diaria con ventana movil de 250 días.
tickerV=c("QQQ")
hastaD=as.Date("2024-11-20")
deD=as.Date("2019-11-20")
per="D"
paridadFX="USDMXN=X"
convertirFX=c(FALSE)
Datos=historico_multiples_precios(tickers=tickerV,de=deD,hasta=hastaD,periodicidad=per,fxRate=paridadFX,whichToFX=convertirFX)
## [1] "Extrayendo RIC 1 de 1 (QQQ), periodicidad D"
## [1] "Extrayendo QQQ..."
## [1] "QQQ extraído de Yahoo Finance..."
## [1] "Se terminó de extraer y procesar un total de 1 tickers desde las BD de Yahoo Finance..."
## [1] "Tickers procesados: QQQ"
rendimientos=Datos$tablaRendimientosCont$QQQ
La desviación estándar convencional:
sigma_fija=sd(rendimientos)
sigma_fija
## [1] 1.615079
La desviación estándar con suavizamiento exponencial con 0.95 y 0.98:
# Volatilidad con suavizamiento exponencial con lambda=0.95:
sigma95Lambda=rollEWSigma(rendimientos,0.95,250)
# Volatilidad con suavizamiento exponencial con lambda=0.98:
sigma98Lambda=rollEWSigma(rendimientos,0.98,250)
La desviación estándar GARCH:
#normal
sigmaGARCHT_norm=rollGARCH(rendimientos,model="sGARCH",LLF="norm",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE,ventana=250)
#t-studen
sigmaGARCHT_std=rollGARCH(rendimientos,model="sGARCH",LLF="std",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE,ventana=250)
#ged
sigmaGARCHT_ged=rollGARCH(rendimientos,model="sGARCH",LLF="ged",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE,ventana=250)
La desviación estándar GJR-GARCH:
#norm
spec <- ugarchspec(
variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0)),
distribution.model = "norm"
)
window_size <- 250
n <- length(rendimientos)
volatility <- numeric(n - window_size + 1)
for (i in window_size:n) {
sub_data <- rendimientos[(i - window_size + 1):i]
fit <- ugarchfit(spec, sub_data)
volatility[i - window_size + 1] <- sigma(fit)[length(sigma(fit))]
}
sigma_GJR_GARCHT_norm = volatility #rollgarch(spec = spec, data = rendimientos, width = 250, refit.every = 1)
#tstudent
spec <- ugarchspec(
variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0)),
distribution.model = "std"
)
window_size <- 250
n <- length(rendimientos)
volatility <- numeric(n - window_size + 1)
for (i in window_size:n) {
sub_data <- rendimientos[(i - window_size + 1):i]
fit <- ugarchfit(spec, sub_data)
volatility[i - window_size + 1] <- sigma(fit)[length(sigma(fit))]
}
sigma_GJR_GARCHT_std = volatility
#sigma_GJR_GARCHT_std = rollgarch(spec = spec, data = rendimientos, width = 250, refit.every = 1)
#ged
spec <- ugarchspec(
variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0)),
distribution.model = "ged"
)
window_size <- 250
n <- length(rendimientos)
volatility <- numeric(n - window_size + 1)
for (i in window_size:n) {
sub_data <- rendimientos[(i - window_size + 1):i]
fit <- ugarchfit(spec, sub_data)
volatility[i - window_size + 1] <- sigma(fit)[length(sigma(fit))]
}
sigma_GJR_GARCHT_ged = volatility
#sigma_GJR_GARCHT_ged= rollgarch(spec = spec, data = rendimientos, width = 250, refit.every = 1)
Estos modelos se pueden contrastar contra la gráfica histórica:
# Gráfica comparativa:
figura2=plot_ly()%>%add_trace(x=~Date,
y=~QQQ,
data=Datos$tablaRendimientosCont,
type="scatter",
mode="lines",
name="Rendimientos QQQ")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+sigma_fija,
type="scatter",
mode="lines",
name="Desviación estándar sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-sigma_fija,
type="scatter",
mode="lines",
name="Desviación estándar inf.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+sigma95Lambda,
type="scatter",
mode="lines",
name="Desviación estándar lambda 95 sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+sigma98Lambda,
type="scatter",
mode="lines",
name="Desviación estándar lambda 98 sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-sigma95Lambda,
type="scatter",
mode="lines",
name="Desviación estándar lambda 95 inf.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-sigma98Lambda,
type="scatter",
mode="lines",
name="Desviación estándar lambda 98 inf.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+sigmaGARCHT_norm,
type="scatter",
mode="lines",
name="Desviación estándar GARCH normal sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-sigmaGARCHT_norm,
type="scatter",
mode="lines",
name="Desviación estándar GARCH normal inf")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+sigmaGARCHT_std,
type="scatter",
mode="lines",
name="Desviación estándar GARCH t-student sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-sigmaGARCHT_std,
type="scatter",
mode="lines",
name="Desviación estándar GARCH t-student inf")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+sigmaGARCHT_ged,
type="scatter",
mode="lines",
name="Desviación estándar GARCH GED sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-sigmaGARCHT_ged,
type="scatter",
mode="lines",
name="Desviación estándar GARCH GED inf")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_norm)), sigma_GJR_GARCHT_norm),
type="scatter",
mode="lines",
name="Desviación estándar GJR GARCH normal sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_norm)), sigma_GJR_GARCHT_norm),
type="scatter",
mode="lines",
name="Desviación estándar GJR GARCH normal inf")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_std)), sigma_GJR_GARCHT_std),
type="scatter",
mode="lines",
name="Desviación estándar GJR GARCH t-student sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_std)), sigma_GJR_GARCHT_std),
type="scatter",
mode="lines",
name="Desviación estándar GJR GARCH t-student inf")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0+c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_ged)), sigma_GJR_GARCHT_ged),
type="scatter",
mode="lines",
name="Desviación estándar GJR GARCH GED sup.")%>%
add_trace(x=Datos$tablaRendimientosCont$Date,
y=0-c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_ged)), sigma_GJR_GARCHT_ged),
type="scatter",
mode="lines",
name="Desviación estándar GJR GARCH GED inf")
figura2
Donde se visualiza que el mejor modelo es el GJR GARCH normal, que al igual que GJR t-student poseen comportamientos similares a los datos.
Tanto los resultados como la teoría muestran la importancia de implementar modelos que conserven información de movimientos “atípicos”, no solo de manera global como es el caso de la desviación estandar fija, sino de manera local como es el caso de los modelos GARCH. La implementación de estos permite no solo establecer intervalos de perdida que reducen la sobre o subestimación del fenómeno estudiado.
Por otro lado se realizó la introducción de los modelos GARCH asimétricos, los cuales son ampliamente utilizados en mercados financieros donde las caídas de precios tienden a generar más volatilidad que los aumentos.
Por ultimo se deja a discreción del usuario la elección del mejor modelo, ya que estos dependerán de los objetivos que se busquen lograr, teniendo en cuenta que: